package com.marketlive.entity;

/*
(C) Copyright MarketLive. 2006. All rights reserved.
MarketLive is a trademark of MarketLive, Inc.
Warning: This computer program is protected by copyright law and international treaties.
Unauthorized reproduction or distribution of this program, or any portion of it, may result
in severe civil and criminal penalties, and will be prosecuted to the maximum extent
possible under the law.
*/

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.hibernate.usertype.UserType;
import org.hibernate.HibernateException;
import org.hibernate.Hibernate;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.PreparedStatement;
import java.io.Serializable;

/**
 * Maps <code>StringPk</code>s to VARCHAR fields in the database.
 */
public class StringPkType implements UserType, Serializable {

    /**
     * Logger.
     */
    private static Log log = LogFactory.getLog(StringPkType.class);

    /**
     * Returns an array of the SQL type codes for the columns mapped by this type.
     * The codes are defined in java.sql.Types.
     *
     * @return a one-element array with the value java.sql.Types.VARCHAR
     * @see java.sql.Types
     */
    public int[] sqlTypes() {
        return new int[]{java.sql.Types.VARCHAR};
    }

    /**
     * Returns the class that is returned by <code>nullSafeGet()</code>.
     *
     * @return the <code>StringPk</code> class
     */
    public Class returnedClass() {
        return StringPk.class;
    }

    /**
     * Compares two instances of the class mapped by this type for persistence equality.
     * If the two instances are null or the same, returns true. If <code>x</code> is null,
     * returns false. If none of these conditions apply, delegates to <code>x.equals(y)</code>.
     *
     * @param x first object to compare
     * @param y second object to compare
     * @return true if the two objects represent the same entity
     * @throws org.hibernate.HibernateException if the operation fails
     */
    public boolean equals(final Object x, final Object y) throws HibernateException {
        if (x == y) {
            return true;
        }
        if (x == null) {
            return false;
        }
        return x.equals(y);
    }

    /**
     * Retrieves a <code>StringPk</code> from a JDBC ResultSet.
     *
     * @param resultSet the result set to examine
     * @param names an array of column names. Only the first element in the array is used.
     * @param o not used
     * @return a <code>StringPk</code> from the given result set, or null if none was found.
     *         The entity type of the returned key is <code>TBD</code>.
     * @throws org.hibernate.HibernateException if an error occurs
     * @throws java.sql.SQLException if an error occurs
     */
    public Object nullSafeGet(final ResultSet resultSet, final String[] names, final Object o)
            throws HibernateException, SQLException {
        String id = (String) Hibernate.STRING.nullSafeGet(resultSet, names[0]);

        if (id == null) {
            return null;
        } else {
            return new StringPk("TBD", id);
        }
    }

    /**
     * Sets the given value as a query parameter on the given statement.
     *
     * @param st the statement to set the value for
     * @param value the value to set
     * @param index the index in the statement to which the value corresponds
     * @throws org.hibernate.HibernateException if an error occurs
     * @throws java.sql.SQLException if an error occurs
     * @see org.hibernate.UserType#nullSafeSet(java.sql.PreparedStatement, Object, int)
     */
    public void nullSafeSet(final PreparedStatement st, final Object value, final int index)
            throws HibernateException, SQLException {
        if (value == null) {
            Hibernate.STRING.nullSafeSet(st, value, index);
        } else {
            StringPk pk = (StringPk) value;
            Hibernate.STRING.nullSafeSet(st, pk.getAsString(), index);
        }
    }

    /**
     * Returns a copy of the given key. Because <code>StringPk</code> is immutable, this
     * implementation returns a reference to the original object.
     *
     * @param stringPk the object to copy. Must be a <code>StringPk</code>.
     * @return a reference to the given object
     * @throws HibernateException if the given object is not an instance of <code>StringPk</code>
     */
    public Object deepCopy(final Object stringPk) throws HibernateException {
        if (!(stringPk instanceof StringPk)) {
            throw new HibernateException("Object must be an instance of StringPk: " + stringPk);
        }
        return stringPk;
    }

    /**
     * Returns false. <code>StringPk</code>s are immutable.
     *
     * @return false
     */
    public boolean isMutable() {
        return false;
    }

    /**
     * Returns a hash code for the given object that is consistent with persistence equality.
     *
     * @param pStringPk the object for which to return a hash code
     * @return the hash code of the given object
     * @throws NullPointerException if <code>pStringPk</code> is null
     * @throws HibernateException if an error occurs
     */
    public int hashCode(Object pStringPk) throws HibernateException {
        return pStringPk.hashCode();
    }

    /**
     * Transforms the given object into a cacheable representation.
     * Casts the given object to <code>Serializable</code>.
     *
     * @param pStringPk the object to transform
     * @return a cacheable form of the given object
     * @throws HibernateException if an error occurs
     */
    public Serializable disassemble(Object pStringPk) throws HibernateException {
        return (Serializable) pStringPk;
    }

    /**
     * Reconstructs an object from its cacheable representation.
     * @param pCached the object to assemble
     * @param pOwner the owner. Not used.
     * @return a reference to <code>pCached</code>
     * @throws HibernateException if an error occurs
     */
    public Object assemble(Serializable pCached, Object pOwner) throws HibernateException {
        return pCached;
    }

    /**
     * Returns the original object.
     *
     * @param pOriginal the original object to merge into the target
     * @param pTarget the target object. Not used.
     * @param pOwner the owner of the object. Not used.
     * @return a reference to <code>pOriginal</code>
     * @throws HibernateException if an error occurs
     */
    public Object replace(Object pOriginal, Object pTarget, Object pOwner) throws HibernateException {
        return pOriginal;
    }
}
